package com.mchat.friend.dao;

import com.mchat.friend.domain.dto.FriendDescribeDTO;
import com.mchat.friend.domain.po.Friend;
import io.r2dbc.spi.Result;
import io.r2dbc.spi.Row;
import io.r2dbc.spi.RowMetadata;
import io.r2dbc.spi.Statement;
import lombok.RequiredArgsConstructor;
import org.reactivestreams.Publisher;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.function.BiFunction;

@RequiredArgsConstructor
@Component
public class FriendDAO {
    private final DatabaseClient databaseClient;
    private  final BiFunction<Row, RowMetadata, Friend> MAP_FUNCTION = (row, rowMetadata) -> {
        Friend friend = new Friend();
        friend.setId(row.get("id",Long.class));
        friend.setUid(row.get("uid",Long.class));
        friend.setFriendId(row.get("friend_id",Long.class));
        friend.setRemarkName(row.get("remark_name",String.class));
        friend.setUserGroup(row.get("user_group",String.class));
        friend.setCreateTime(row.get("create_time", LocalDateTime.class));
        return friend;
    };
    public Mono<Long> saveFriend(Friend friend1,Friend friend2){
        String sql= """
                insert into tb_friend (uid, friend_id, remark_name, user_group, create_time)
                values ($1,$2,$3,$4,current_timestamp)
                on conflict (uid,friend_id) do nothing
                """;
        return databaseClient.inConnection(connection -> {
            Statement statement = connection.createStatement(sql);
            statement.bind(0,friend1.getUid())
                    .bind(1,friend1.getFriendId())
                    .bind(2,friend1.getRemarkName())
                    .bind(3,friend1.getUserGroup())
                    .add();
            Publisher<? extends Result> execute = statement
                    .bind(0, friend2.getUid())
                    .bind(1, friend2.getFriendId())
                    .bind(2, friend2.getRemarkName())
                    .bind(3, friend2.getUserGroup())
                    .execute();
            return Mono.from(execute).flatMap(result -> Mono.from(result.getRowsUpdated()));
        });
    }
    public Mono<Long>deleteFriend(long uid1,long uid2){
        return databaseClient.sql("DELETE FROM tb_friend WHERE (uid, friend_id) IN ((:uid1, :uid2), (:uid2, :uid1))")
                .bind("uid1",uid1)
                .bind("uid2",uid2)

                .fetch().rowsUpdated();
    }
    public Mono<Boolean>selectExist(long uid1,long uid2){
        return databaseClient.sql("select exists(select 1 from tb_friend where uid=:uid1 and friend_id=:uid2)")
                .bind("uid1",uid1)
                .bind("uid2",uid2)
                .map(row->row.get(0,Boolean.class))
                .one();
    }
    public Mono<Long>updateDescribe(FriendDescribeDTO describe){
        String sql= """
                update tb_friend set remark_name=$1 ,user_group=$2
                where uid=$3 and friend_id=$4
                """;
        return databaseClient.inConnection(connection -> {
            Publisher<? extends Result> execute = connection.createStatement(sql)
                    .bind(0, describe.getRemarkName())
                    .bind(1, describe.getUserGroup())
                    .bind(2, describe.getUid())
                    .bind(3, describe.getFriendId())
                    .execute();
            return Mono.from(execute).flatMap(result->Mono.from(result.getRowsUpdated()));
        });
    }
    public Flux<Friend> getFriend(long uid){
        String slq="""
                select * from tb_friend where uid=$1
                """;
        return databaseClient.inConnectionMany(connection -> {
            Publisher<? extends Result> execute = connection.createStatement(slq)
                    .bind(0, uid)
                    .fetchSize(100)
                    .execute();
            return Flux.from(execute).flatMap(result -> result.map(MAP_FUNCTION));
        });

    }

}
